package ikudyk.university;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Main {

    public static void main(String[] args) {

    }

    public static Queue<Token> getPolishNote(LinkedList<Token> tokens) throws Exception {
        Queue<Token> result = new LinkedList<Token>();
        Stack<Token> operatorStack = new Stack<Token>();
        while(!tokens.isEmpty()) {
            Token topToken = tokens.peek();
            if(topToken.getType() == Token.BAD_TOKEN) {
                throw new Exception("Bad token was detected: " + topToken.getValue());
            }
            if(topToken.getType() == Token.NUMBER || topToken.getType() == Token.BOOLEAN) {
                result.add(tokens.pop());
            } else if(topToken.getType() == Token.OPERATOR) {
                Operator op1 = Operator.getOperatorByString(topToken.getValue());
                for(int i = 0; i < operatorStack.size(); i++) {
                    if(operatorStack.peek().getType() != Token.OPERATOR) {
                        break;
                    } else {
                        Operator op2 = Operator.getOperatorByString(operatorStack.peek().getValue());
                        while(!op1.isRightAssociative() && op1.getPriority() <= op2.getPriority()
                                || op1.isRightAssociative() && op1.getPriority() < op2.getPriority()) {
                            result.add(operatorStack.pop());
                        }
                    }
                }
                operatorStack.add(tokens.pop());
            } else if(topToken.getType() == Token.WHITESPACES) {
                tokens.pop();
            } else if(topToken.getType() == Token.BRACKET_OPEN) {
                operatorStack.add(tokens.pop());
            } else if(topToken.getType() == Token.BRACKET_CLOSE) {
                boolean areBracketsBalanced = false;
                while(!operatorStack.isEmpty()) {
                    if(operatorStack.peek().getType() == Token.BRACKET_OPEN) {
                        operatorStack.pop();
                        areBracketsBalanced = true;
                        break;
                    }
                    result.add(operatorStack.pop());
                }
                if(!areBracketsBalanced) {
                    throw new Exception("Unbalanced brackets construction was detected!");
                }
                tokens.pop();
            }
        }
        while(!operatorStack.isEmpty()) {
            if(operatorStack.peek().getType() == Token.BRACKET_OPEN) {
                throw new Exception("Unbalanced brackets construction was detected!");
            }
            result.add(operatorStack.pop());
        }
        return result;
    }

    public static Token compile(Queue<Token> tokens) throws Exception {
        Stack<Token> variablesStack = new Stack<Token>();
        while(!tokens.isEmpty()) {
            if(tokens.peek().getType() == Token.NUMBER || tokens.peek().getType() == Token.BOOLEAN) {
                variablesStack.add(tokens.poll());
            } else if(tokens.peek().getType() == Token.OPERATOR) {
                Operator operator = Operator.getOperatorByString(tokens.peek().getValue());
                if(variablesStack.size() < operator.getOperandQuantity()) {
                    throw new Exception("Not enough operands for the operator: " + tokens.peek());
                }
                LinkedList<Token> operands = new LinkedList<Token>();
                for(int i = 0; i < operator.getOperandQuantity(); i++) {
                    if(variablesStack.peek().getType() != operator.getOperandTokenType()) {
                        throw new Exception("Bad operand type: " + variablesStack.peek().getType() +
                                " instead of " + operator.getOperandTokenType());
                    }
                    operands.add(variablesStack.pop());
                }
                calculateSafe(operator, operands);
            }
        }
    }

    public void calculateSafe
}
